package com.superbit.web.filter;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.superbit.model.feature.AuthortyService;
import com.superbit.model.feature.MessageLogService;
import com.superbit.web.excep.AccessBusyException;
import com.superbit.web.excep.AccessLimitException;
import com.superbit.web.excep.NoLoginException;
import com.superbit.web.listener.ServiceBeanFactory;
import com.superbit.web.utils.HttpRequestUtil;
import com.superbit.web.utils.SessionUserUtil;
public class AuthorityFilter implements Filter {
	
	private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
	private int limitAccessCount = 500;
	private AuthortyService authortyService = null;
	@Autowired
	private MessageLogService messageLogService = null;


	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		this.authortyService = ServiceBeanFactory.getBean(AuthortyService.class);
		this.messageLogService = ServiceBeanFactory.getBean(MessageLogService.class);
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest)request;
		String[] roles = SessionUserUtil.getLoginRole(req.getSession());
		String uri = HttpRequestUtil.getActualURI(req);
		String cmd = StringUtils.trimToEmpty(req.getParameter("cmd"));
		boolean hasright = this.hasAuthorty(roles, uri, cmd);
		if(!hasright){//没有相关权限时, 提示错误
			if(roles.length==1&&AuthortyService.ROLE_NOLOGIN==roles[0]){//无用户登陆
				throw new NoLoginException(uri, cmd);
			}else{//用户登陆但无对应权限			
				throw new AccessLimitException(SessionUserUtil.getLoginUserId(req.getSession()),uri,cmd);
			}
		}
		
		//判断用户访问频率
		String nowTime = dateFormat.format(new Date());
		HttpSession session = req.getSession();
		if(!nowTime.equals(session.getAttribute("accesstime"))){
			session.setAttribute("accesstime", nowTime);
			session.setAttribute("accesscount",1);
		}else{//同一分钟内，计数
			Integer count = (Integer)session.getAttribute("accesscount");
			if(count==null)count=0;
			if(count<limitAccessCount){
				count = count+1;
				session.setAttribute("accesscount",count);	
			}else{//访问过于频繁时,提示错误   目前此种数量限制在同一个session的高并发下，实际上得不到有限控制
				count = count+1;
				session.setAttribute("accesscount",count);	
				throw new AccessBusyException(SessionUserUtil.getLoginUserId(req.getSession()),count);
			}
		}
		
		//记录操作日志
		boolean needLogOperation = needLogOperation(uri,cmd);
		if(!needLogOperation){
			chain.doFilter(request, response);
		}else{
			try{
				chain.doFilter(request, response);	
				logOperation(uri,cmd,SessionUserUtil.getLoginUserId(session),request,true); //记录用户操作成功
			}catch(RuntimeException|IOException |ServletException e){
				logOperation(uri,cmd,SessionUserUtil.getLoginUserId(session),request,false); //记录用户操作失败
				throw e;
			}
		}
	}
	
	/**记录操作日志
	 * @param uri
	 * @param cmd
	 * @param loginUserId
	 * @param request
	 */
	private void logOperation(String uri, String cmd, Integer loginUserId, ServletRequest request,boolean sucessfull) {
		Map<String,String> parammap = this.getRequestParamMap(request);
		parammap.remove("newpwd");
		parammap.remove("oldpwd");
		parammap.remove("password");
		parammap.remove("foundpwd");
		messageLogService.logUserOpertiaon(uri,cmd,loginUserId,parammap,sucessfull);
	}

	/**判断是否有权限访问URL
	 * @param role
	 * @param uri
	 * @param cmd
	 * @return
	 */
	private boolean hasAuthorty(String[] roles,String uri,String cmd){
		List<String> list = authortyService.getAuthortyRoleByURI(uri, cmd);
		if(list==null){
			return true;  //未定义时全部通过
		}else{
			boolean hasauthorty = false;
			List<String> rolelist = Arrays.asList(roles);
			for(String allow:list){
				if(rolelist.contains(allow)){
					hasauthorty = true;
					break;
				}
			}
			return hasauthorty;
		}
	}
	
	/**判断是否需要进行操作日志的记录
	 * @param uri
	 * @param cmd
	 * @return
	 */
	private boolean needLogOperation(String uri,String cmd){
		return authortyService.needLogOperation(uri, cmd);
	}
	
	/**获取参数数据
	 * @param req
	 * @return
	 */
	private Map<String,String> getRequestParamMap(ServletRequest req){
		Map<String,String[]> map = req.getParameterMap();
		Map<String,String> map2 = new HashMap<String,String>();
		for(String key : map.keySet()){
			String[] values = map.get(key);
			if(values.length==1){
				map2.put(key, values[0]);
			}else{
				map2.put(key, Arrays.asList(values).toString());
			}
		}
		return map2;
	}

	@Override
	public void destroy() {
		//
	}

}
